import time
import logging
import requests
import base64
import hashlib
import json
from datetime import datetime
from typing import List, Optional, Dict
from pathlib import Path
from tenacity import retry, stop_after_attempt, wait_exponential
from apscheduler.schedulers.background import BackgroundScheduler
from apscheduler.triggers.cron import CronTrigger
from pydantic import BaseModel, ValidationError
from secure_config import SecureConfigLoader


# --------------------------
# 基础模型验证
# --------------------------
class MessageBase(BaseModel):
    msgtype: str
    image: Optional[Dict[str, str]] = None


# --------------------------
# 安全日志格式化
# --------------------------
class SafeFormatter(logging.Formatter):
    def format(self, record):
        message = super().format(record)
        if 'webhook/send?key=' in message:
            message = message.split('webhook/send?key=')[0] + 'webhook/send?key=***'
        return message


# --------------------------
# 同步企业微信图片机器人
# --------------------------
class SyncQyWechatBot:
    def __init__(self, config):
        self.config = config
        webhook_key = self.config['qywxapi']['webhook_key']
        self.webhook_url = f"https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key={webhook_key}"
        self.scheduler = BackgroundScheduler()
        self.scheduler.configure(
            job_defaults={
                'coalesce': True,  # 合并积压任务
                'max_instances': 1,  # 防止并发过高
                'misfire_grace_time': None
            }
        )
        self._setup_logging()
        self.scheduler.start()

    def _setup_logging(self):
        """日志配置"""
        self.logger = logging.getLogger('SyncQyWechatBot')
        self.logger.setLevel(logging.INFO)
        formatter = SafeFormatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
        ch = logging.StreamHandler()
        ch.setFormatter(formatter)
        self.logger.addHandler(ch)
        self.logger.propagate = False

    @retry(
        stop=stop_after_attempt(3),
        wait=wait_exponential(multiplier=1, min=5, max=10)
    )
    def send_image(self, image_path: str):
        """同步发送图片"""
        start_time = time.perf_counter()  # 发送耗时记录
        try:
            # 处理并验证图片
            image_data = self._process_image(image_path)
            message = MessageBase(
                msgtype="image",
                image=image_data
            )

            # 验证消息格式
            if not self._validate_message(message):
                return False

            # 同步发送请求
            response = requests.post(
                self.webhook_url,
                json=message.model_dump(),
                timeout=10
            )
            result = response.json()

            if result.get('errcode') != 0:
                error_msg = f"发送失败: {result['errmsg']}({result['errcode']})"
                self.logger.error(error_msg)
                raise Exception(error_msg)

            self.logger.info("图片发送成功")
            return True

        except Exception as e:
            self.logger.error(f"发送失败: {str(e)}")
            raise
        finally:
            elapsed = time.perf_counter() - start_time
            self.logger.debug(f"发送耗时: {elapsed:.3f}s")
            if elapsed > 5.0:  # 超时警告
                self.logger.warning("发送响应时间过长")

    def _process_image(self, image_path: str) -> Dict[str, str]:
        """处理图片编码"""
        with open(image_path, "rb") as f:
            image_data = f.read()

        if len(image_data) > 2 * 1024 * 1024:
            raise ValueError("图片大小超过2MB限制")

        return {
            "base64": base64.b64encode(image_data).decode('utf-8'),
            "md5": hashlib.md5(image_data).hexdigest()
        }

    def _validate_message(self, message: MessageBase) -> bool:
        """消息格式验证"""
        try:
            MessageBase(**message.model_dump())
            return True
        except ValidationError as e:
            self.logger.error(f"消息格式错误: {str(e)}")
            return False

    # --------------------------
    # 定时任务管理
    # --------------------------
    def schedule_image_task(self, image_path: str, schedule_config: dict):
        """
        安排定时发图任务
        :param image_path: 图片路径
        :param schedule_config: 调度配置
        """
        trigger = CronTrigger(**schedule_config)
        self.scheduler.add_job(
            self.send_image,
            trigger=trigger,
            args=[image_path],
            id=f"image_task_{image_path}",
            replace_existing=True,
            next_run_time=datetime.now()
        )
        self.logger.info(f"图片定时任务已注册: {image_path}")

    def shutdown(self):
        """安全关闭"""
        self.scheduler.shutdown()
        self.logger.info("系统已关闭")


# --------------------------
# 使用示例
# --------------------------
# if __name__ == "__main__":
#     config = SecureConfigLoader.load("config.yaml")
#     bot = SyncQyWechatBot(config)
#
#     # 同步发送测试
#     try:
#         bot.send_image("./screenshots/screenshot.png")
#     except Exception as e:
#         print(f"发送失败: {str(e)}")
#
#     # 定时任务示例
#     bot.schedule_image_task(
#         image_path="./screenshots/daily_report.png",
#         schedule_config={'hour': 9, 'minute': 0}  # 每天9点发送
#     )
#
#     try:
#         while True:
#             time.sleep(1)
#     except KeyboardInterrupt:
#         bot.shutdown()